package genetica.mutacion;

import genetica.cromosomas.Cromosoma;
import genetica.cromosomas.genes.Gen;

import java.util.ArrayList;
import java.util.Random;

public class MutacionHeuristica extends AlgoritmoMutacion {
	int nGenes;

	public void setGenesHeuristica(int genes) {
		this.nGenes = genes;
	}

	public int getGenesHeuristica() {
		return nGenes;
	}

	public MutacionHeuristica(double pMutacion, int nGenes) {
		super(pMutacion);
		this.nGenes = nGenes;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void mutacion(Cromosoma original) {
		Random r = new Random();
		if (r.nextDouble() < pMutacion) {
			ArrayList<Gen> genes = new ArrayList<Gen>();
			ArrayList<Integer> todasLasPosiciones = new ArrayList<Integer>();

			for (int i = 0; i < original.getGenes().size(); i++) {
				todasLasPosiciones.add(i);
			}
			Integer[] posiciones= new Integer[nGenes];
			for (int i = 0; i < nGenes; i++) {
				posiciones[i] = todasLasPosiciones.remove(r
						.nextInt(todasLasPosiciones.size()));
				genes.add(original.getGenes().get(posiciones[i]));
			}
			int nGenesPermutados = factorial(nGenes);

			Cromosoma[] nuevos = new Cromosoma[nGenesPermutados];
			ArrayList<ArrayList<Gen>> permutas = new ArrayList<ArrayList<Gen>>();
			calculaPermutaciones(permutas, genes, new ArrayList<Gen>());
			for (int i = 0; i < nGenesPermutados; i++) {
				nuevos[i] = original.clone();
				for (int j = 0; j < nGenes; j++) {
					nuevos[i].getGenes().set(posiciones[j], permutas.get(i).get(j));
				}
				nuevos[i].calcularFenotipo();
				nuevos[i].evalua();
			}
			Cromosoma mejor = nuevos[0];
			if (Cromosoma.getMaximizar()) {
				for (int i = 1; i < nGenesPermutados; i++) {
					if (mejor.compareTo(nuevos[i]) > 0) {
						mejor = nuevos[i];
					}
				}
			} else {

				for (int i = 1; i < nGenesPermutados; i++) {
					if (mejor.compareTo(nuevos[i]) < 0) {
						mejor = nuevos[i];
					}
				}
			}
			original.setGenes((ArrayList<Gen>) mejor.getGenes().clone());
		}

	}

	public int factorial(int n) {
		int result = 1;
		for (result = 1; result < n; result++)
			result *= result;
		return result;
	}

	@SuppressWarnings("unchecked")
	private void calculaPermutaciones(ArrayList<ArrayList<Gen>> resultado,
			ArrayList<Gen> genesRestantes, ArrayList<Gen> permuta) {
		for (int i = 0; i < genesRestantes.size(); i++) {
			ArrayList<Gen> genesTemp = (ArrayList<Gen>) genesRestantes.clone();
			ArrayList<Gen> nuevaPermuta = (ArrayList<Gen>) permuta.clone();
			Gen genPermutado = genesTemp.remove(i);
			nuevaPermuta.add(genPermutado);
			if (nuevaPermuta.size() == nGenes) {
				resultado.add(nuevaPermuta);
			} else {
				calculaPermutaciones(resultado, genesTemp, nuevaPermuta);
			}

		}
	}

	public String toString() {
		return "Mutación por metodo heuristico";
	}
}
